using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;

using webcam = Microsoft.Robotics.Services.WebCam.Proxy;
using Microsoft.Ccr.Adapters.WinForms;

namespace UrbanCam
{
	[Contract(Contract.Identifier)]
	[DisplayName("Urban Cam")]
	[Description("Urban Cam service (no description provided)")]
	class UrbanCamService : DsspServiceBase
	{
        webcam.WebCamOperations webcamPort = null;
        webcam.WebCamOperations webcamSubscribePort = null;

		[ServiceState]
		UrbanCamState _state = new UrbanCamState();
		
		[ServicePort("/UrbanCam", AllowMultipleInstances = true)]
		UrbanCamOperations _mainPort = new UrbanCamOperations();
		
		public UrbanCamService(DsspServiceCreationPort creationPort)
			: base(creationPort)
		{
		}
		
		protected override void Start()
		{
            Activate(Arbiter.Interleave(
                new TeardownReceiverGroup
                (
                    Arbiter.Receive<DsspDefaultDrop>(false, _mainPort, DropHandler)
                ),
                new ExclusiveReceiverGroup
                (
                    Arbiter.ReceiveWithIterator<Connect>(true, _mainPort, ConnectHandler)
                ),
                new ConcurrentReceiverGroup
                (
                    Arbiter.Receive<DsspDefaultLookup>(true, _mainPort, DefaultLookupHandler)
                )
            ));

            DirectoryInsert();

            WinFormsServicePort.Post(new RunForm(CreateAppForm));			
		}

        CamImageForm _form;

        CamImageForm CreateAppForm()
        {
            _form = new CamImageForm(_mainPort);
            return _form;
        }

        void DropHandler(DsspDefaultDrop drop)
        {
            if (_form != null)
            {
                CamImageForm form = _form;
                _form = null;

                WinFormsServicePort.FormInvoke(
                    delegate()
                    {
                        if (!form.IsDisposed)
                        {
                            form.Dispose();
                        }
                    }
                );
            }

            base.DefaultDropHandler(drop);
        }

        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public virtual IEnumerator<ITask> ConnectHandler(Connect update)
        {
            string camUrl = "";

            if (update.Body.CamUriName == null)
                camUrl = "Camera1";
            else
                camUrl = update.Body.CamUriName;

            webcamPort = ServiceForwarder<webcam.WebCamOperations>("/" + camUrl);
            webcamSubscribePort = new webcam.WebCamOperations();
            yield return Arbiter.Choice<SubscribeResponseType, W3C.Soap.Fault>(
                webcamPort.Subscribe(webcamSubscribePort),
                delegate(SubscribeResponseType response)
                {
                    Activate(Arbiter.ReceiveWithIterator<webcam.UpdateFrame>(false, webcamSubscribePort, updateFrameHandler));

                    WinFormsServicePort.Post(new FormInvoke(delegate()
                    {
                        try
                        {
                            _form.label1.Text = camUrl;
                        }
                        catch (Exception ex)
                        {
                            LogInfo(ex.ToString());
                            Console.WriteLine(ex);
                        }
                    }));
                },
                delegate(W3C.Soap.Fault fault)
                {
                    Console.WriteLine("CAM Failed to Subscribe " + fault.ToException());
                });

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }

        public IEnumerator<ITask> updateFrameHandler(webcam.UpdateFrame up)
        {
            webcam.QueryFrameRequest req = new Microsoft.Robotics.Services.WebCam.Proxy.QueryFrameRequest();
            req.Format = System.Drawing.Imaging.ImageFormat.Bmp.Guid;
            req.Size = new Microsoft.Robotics.PhysicalModel.Proxy.Vector2(128, 128);
            yield return Arbiter.Choice<webcam.QueryFrameResponse, W3C.Soap.Fault>(
                webcamPort.QueryFrame(req),
                delegate(webcam.QueryFrameResponse response)
                {
                    WinFormsServicePort.Post(new FormInvoke(delegate()
                    {
                        try
                        {
                            System.IO.MemoryStream mem = new System.IO.MemoryStream(response.Frame);
                            _form.pictureBox1.Image = new System.Drawing.Bitmap(mem);
                        }
                        catch (Exception ex)
                        {
                            LogInfo(ex.ToString());
                            Console.WriteLine(ex);
                        }
                    }));
                },
                delegate(W3C.Soap.Fault fault)
                {
                });
            Activate(Arbiter.ReceiveWithIterator<webcam.UpdateFrame>(false, webcamSubscribePort, updateFrameHandler));
            yield break;
        }
	}
}


